﻿// -----------------------------------------------------------------------
// <copyright file="GameBoardViewModel.cs" company="R&R">
// TODO: Update copyright text.
// </copyright>
// -----------------------------------------------------------------------

#region Imports
using System;
using System.Collections.ObjectModel;
using System.Configuration;
using System.Linq;
using System.Windows;
using System.Reflection;
using System.IO;
#endregion Imports

namespace Domino
{
    public class GameBoardViewModel : BaseViewModel
    {
        #region Command declarations
        public RelayCommand<bool> StartGameCommand { get; private set; }
        public RelayCommand<TileModel> PlayTileCommand { get; private set; }
        public RelayCommand NextMoveCommand { get; private set; }
        #endregion Command declarations

        const int minPlayerCount = 2;

        #region Properties
        private GameModel model;
        public GameModel Model
        {
            get { return model; }
            set { model = value; RaisePropertyChanged("Model"); }
        }

        private ObservableCollection<int> allowedPlayerCount = new ObservableCollection<int>();
        public ObservableCollection<int> AllowedPlayerCount
        {
            get { return allowedPlayerCount; }
            set
            {
                allowedPlayerCount = value; RaisePropertyChanged("AllowedPlayerCount");
                if (allowedPlayerCount != null && allowedPlayerCount.Count() == 1) PlayerCount = allowedPlayerCount.First();
            }
        }

        private int playerCount = -1;
        public int PlayerCount
        {
            get { return playerCount; }
            set
            {
                playerCount = value; RaisePropertyChanged("PlayerCount");

                var playerNames = new ObservableCollection<PlayerModel>();
                for (int i = 1; i <= playerCount; i++)
                {
                    playerNames.Add(new PlayerModel
                       {
                           Label = "Player " + i,
                           Name = playerNames.Any() ? (i == 2 ? Environment.UserName : "Player " + i) : "Computer",
                           IsEnabled = playerNames.Any()
                       });
                }
                PlayerNames = playerNames;
            }
        }

        private ObservableCollection<PlayerModel> playerNames = new ObservableCollection<PlayerModel>();
        public ObservableCollection<PlayerModel> PlayerNames
        {
            get { return playerNames; }
            set { playerNames = value; RaisePropertyChanged("PlayerNames"); }
        }

        private eGameType selectedGameType;
        public eGameType SelectedGameType
        {
            get { return selectedGameType; }
            set
            {
                selectedGameType = value; RaisePropertyChanged("SelectedGameType");
                RaisePropertyChanged("AppTitle");
            }
        }

        public string AppTitle
        {
            get
            {
                var title = String.Empty;

                object[] attributes = Assembly.GetExecutingAssembly().GetCustomAttributes(typeof(AssemblyTitleAttribute), false);
                if (attributes.Length > 0)
                {
                    AssemblyTitleAttribute titleAttribute = (AssemblyTitleAttribute)attributes[0];
                    if (titleAttribute.Title != "") title = titleAttribute.Title;
                }

                if (String.IsNullOrEmpty(title)) title = Path.GetFileNameWithoutExtension(Assembly.GetExecutingAssembly().CodeBase);
                title = String.Format("{0} : {1}", title, SelectedGameType.ToString());

                return title;
            }
        }

        private eTileOrientation boneyardOrientation = eTileOrientation.Vertical;
        public eTileOrientation BoneyardOrientation
        {
            get { return boneyardOrientation; }
            set { boneyardOrientation = value; RaisePropertyChanged("BoneyardOrientation"); }
        }

        private eTileOrientation playerOrientation = eTileOrientation.Vertical;
        public eTileOrientation PlayerOrientation
        {
            get { return playerOrientation; }
            set { playerOrientation = value; RaisePropertyChanged("PlayerOrientation "); }
        }

        private eTileOrientation boardOrientation = eTileOrientation.Horizontal;
        public eTileOrientation BoardOrientation
        {
            get { return boardOrientation; }
            set { boardOrientation = value; RaisePropertyChanged("BoardOrientation"); }
        }

        private eTileOrientation boardOrientationPair = eTileOrientation.Vertical;
        public eTileOrientation BoardOrientationPair
        {
            get { return boardOrientationPair; }
            set { boardOrientationPair = value; RaisePropertyChanged("BoardOrientationPair"); }
        }
        #endregion Properties

        private PlayerModel playerRotation;
        public PlayerModel PlayerRotation
        {
            get { return playerRotation; }
            set { playerRotation = value; RaisePropertyChanged("PlayerRotation"); }
        }

#if TEST
        public RelayCommand StressTestCommand { get; private set; } 
#endif

        #region Constructors
        public GameBoardViewModel()
        {
            int maxPlayerCount = Convert.ToInt32(ConfigurationManager.AppSettings["MaxPlayerCount"]);
            var allowedPlayerCount = new ObservableCollection<int>();
            for (int i = minPlayerCount; i <= maxPlayerCount; i++) allowedPlayerCount.Add(i);
            AllowedPlayerCount = allowedPlayerCount;
            PlayerCount = minPlayerCount;

#if TEST
            StressTestCommand = new RelayCommand(new Action<object>((parameter) =>
    {
        int runCount = -1;
        if (Int32.TryParse(Microsoft.VisualBasic.Interaction.InputBox("Enter", "Run count", "100"), out runCount))
            for (int i = 0; i < runCount; i++) { StartGameCommand.Execute(null); Thread.Sleep(1000); }
    })); 
#endif

            StartGameCommand = new RelayCommand<bool>(new Action<bool>((isNewGame) =>
            {
                if (isNewGame) PlayerRotation = null;

                var players = new ObservableCollection<PlayerModel>(PlayerNames);
                var lastPlayer = Model == null ? null : Model.PlayerRotation;
                Model = new GameModel(players, lastPlayer, this.SelectedGameType)
                {
                    BoneyardOrientation = this.BoneyardOrientation,
                    PlayerOrientation = this.PlayerOrientation,
                    BoardOrientation = this.BoardOrientation,
                    BoardOrientationPair = this.BoardOrientationPair
                };

                Model.StartGame(isNewGame);
            }));

            PlayTileCommand = new RelayCommand<TileModel>(new Action<TileModel>((parameter) =>
            {
                if (parameter != null)
                {
                    switch (parameter.TileLocation)
                    {
                        case eTileLocation.BoneYard:
                            Model.AddToPlayerFromBoneyard(parameter);
                            break;

                        case eTileLocation.Player:
                            Model.AddToBoardFromPlayer(parameter);
                            break;
                    }
                }
            })) { OnSameThread = true };

            NextMoveCommand = new RelayCommand(new Action<object>((parameter) =>
            {
                TileModel playableTile = Model.CurrentPlayer.Tiles.Where(t => t.IsPlayable).FirstOrDefault();
                if (playableTile == null)
                {
                    while (Model.CurrentPlayer.Tiles.Where(t => t.IsPlayable).FirstOrDefault() == null)
                    {
                        playableTile = Model.PickRandomTile(Model.CurrentPlayer.Tiles.Where(t => t.IsPlayable));
                        if (playableTile == null) // no tiles to play: keep adding from boneyard to player
                        {
                            if (Model.BoneYard.None()) break; // Exit if boneyard is exhausted

                            var bone = Model.PickRandomTile(Model.BoneYard);
                            if (bone != null) PlayTileCommand.Execute(bone);
                        }
                        else break; // have tiles to play
                    }
                }

                playableTile = Model.PickRandomTile(Model.CurrentPlayer.Tiles.Where(t => t.IsPlayable));
                PlayTileCommand.Execute(playableTile);
            }));
        }
        #endregion Constructors

        #region Events
        public delegate void GameStartEventHandler(object sender, GameStartEventArgs e);
        public delegate void CurrentPlayerSetEventHandler(object sender, CurrentPlayerSetEventArgs e);
        public delegate void PlayerActionEventHandler(object sender, PlayerActionEventArgs e);

        public event GameStartEventHandler GameStarted;
        protected virtual void OnGameStarted(GameStartEventArgs e)
        {
            if (GameStarted != null) GameStarted(this, e);
        }

        public event CurrentPlayerSetEventHandler CurrentPlayerSet;
        protected virtual void OnCurrentPlayerSet(CurrentPlayerSetEventArgs e)
        {
            if (CurrentPlayerSet != null) CurrentPlayerSet(this, e);
        }

        public event PlayerActionEventHandler PlayerAction;
        protected virtual void OnPlayerAction(PlayerActionEventArgs e)
        {
            if (PlayerAction != null) PlayerAction(this, e);
        }
        #endregion Events
    }
}
